In parallel to read/write operations (user load), storage systems often execute multiple types of background tasks, such as reconstruction of parity data, defragmentation, and garbage collection. The priority of tasks usually depends on the state of the system. In a typical case, user load has the highest priority in order to achieve the desired quality of service. When a failure occurs, the missing parity data must be reconstructed with high priority (RAID rebuilding is an example of such reconstruction) in order to recover the expected resiliency level, that is the number of failures that can be tolerated without data loss. The priority of such reconstruction may depend on the current resiliency level. In a system running out of space, writes should be slowed down and the released resources should be assigned to garbage collection. Even in a healthy system, maintenance tasks, such as garbage collection and defragmentation, should not be starved regardless of their lower priority.
Here, the following notation is used below: load type (hereinafter load) denotes a class of tasks of similar characteristic, for example, writes and background tasks; load source (hereinafter source) denotes a part of the system that produces tasks of a certain load type. Load sources are, for instance, software components admitting write/read operations or performing background tasks.
The priorities of loads have to be enforced by some mechanism that divides resources between them according to a given policy (NPL 1, 2). The mechanism should also ensure that the system works with the highest performance possible, and that lower priority loads proceed faster if higher priority loads do not utilize their share.